/* compile.c - Copyright (c) 2006 Helmar Wodtke
   You'll find here the compiler parts for 4p. */

#include <stdlib.h>
#include <stdio.h>

#include "4p.h"

cell *cp,			/* compilation trace pointer         */
 *cpmax,			/* maximum compilation trace pointer */
 *cpmin,			/* minimum compilation trace pointer */
 *cpfrom;			/* current compilation starts here   */
cell stopmark;

#define INCREMENT(pt)      \
  if (++pt == cpmax)       \
    pt = cpmin;

#define INCREMENT_CP       \
  INCREMENT (cp)           \
  if (cp == cpfrom)        \
    INCREMENT (cpfrom)

#define DECREMENT(pt)      \
  if (--pt < cpmin)        \
    pt = cpmax - 1;

void
seal (void)
{
  cpfrom = cp;
  return;
}

void
compile_comma (cell a)
{
  *(cell *)* cp = a;
  *cp += sizeof (cell);
  return;
}

void
compile (cell a)
{
  cell n = *cp + sizeof (cell);
  *(cell *) * cp = a;
  INCREMENT_CP
  *cp = n;
  return;
}

void
revoke_last (void)
{
  if (cp == cpfrom)
    {
      fprintf (stderr, "could not revoke - internal error\n");
      exit (-1);
    }
  DECREMENT (cp)
  return;
}

static int
inlined_ (cell * p, cell * ip)
{
  cell *t;
  while (ip != cp)
    {
      if (*p == stopmark)
        return 0;
      if (*(t = (cell *) * ip) != *p)
	return 0;
      INCREMENT (ip)
      p += (cell *) * ip - t;
    }
  return *p == stopmark ? -1 : 0;
}

int
sequence (cell * p)
{
  cell *ip = cp;
  DECREMENT (ip)
  if (*(cell **) * ip == p)
    return -1;
  if (NATIVE(p))
    return 0;
  for (ip = cp; ip != cpfrom; )
    {
      DECREMENT (ip)
      if (*(cell *) * ip == *p)
	if (inlined_ (p, ip))
	  return -1;
    }
  return 0;
}

cell
lastcall (void)
{
  cell *r = cp;
  if (cp == cpfrom)
    return 0;
  DECREMENT (r)
  return *r;
}

cell
before (cell count)
{
  cell *r = cp;
  while (count-- > 0)
    {
      if (r == cpfrom)
	return 0;
      DECREMENT (r);
    }
  return *r;
}
